package com.weijian.common.interceptor;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.weijian.common.result.BaseContext;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.WebUtils;

import java.time.Duration;

import static com.weijian.common.contants.SystemConstants.JWT_SALT;
import static com.weijian.common.contants.SystemConstants.JWT_TOKEN_EXPIRE_TIME_SECONDS;


/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {


    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法，直接放行
            return true;
        }
        //1、从请求头中获取令牌
        Cookie cookie = WebUtils.getCookie(request, "jwt");
        if (cookie == null || StrUtil.isBlank(cookie.getValue())) {
            response.setStatus(401);
            return false;
        }
        String token = cookie.getValue();

        //2、校验令牌
        try {
            JWT jwt = JWTUtil.parseToken(token).setKey(JWT_SALT.getBytes());
            // 签名 + 时间一次性校验
            JWTValidator.of(jwt)
                    .validateAlgorithm(JWTSignerUtil.hs256(JWT_SALT.getBytes()))
                    .validateDate(DateUtil.date());
            // 检查是否需要刷新token
            long exp = Convert.toLong(jwt.getPayload("exp"));
            long now = DateUtil.currentSeconds();
            // 如果剩余时间少于5分钟，生成新token并返回给客户端
            if (exp - now < 5 * 60) { // 30分钟
                String newToken = JWT.create()
                        .setPayload("user_id", jwt.getPayload().getClaim("user_id"))
                        // Hutool 会自动将 Date 转成 exp（秒级时间戳）
                        .setExpiresAt(DateUtil.offsetSecond(DateUtil.date(), JWT_TOKEN_EXPIRE_TIME_SECONDS))
                        .setKey(JWT_SALT.getBytes())
                        .sign();

                ResponseCookie newCookie = ResponseCookie
                        .from("jwt", newToken)          // cookie 名
                        .path("/")                   // 作用域
                        .httpOnly(true)              // 防 XSS
                        .sameSite("Lax")             // 防 CSRF
                        .maxAge(Duration.ofSeconds(JWT_TOKEN_EXPIRE_TIME_SECONDS))
                        .build();
                response.addHeader(HttpHeaders.SET_COOKIE, newCookie.toString());

            }
            //注意这里用了hutool工具，得到的object类不能强转，需要需要用其自带的工具转换
            Integer userId = Convert.toInt(jwt.getPayload("user_id"));
            BaseContext.setCurrentId(userId);
            //3、通过，放行
            return true;
        } catch (Exception ex) {
            log.error("校验请求头中token失败：{}", ex.getMessage());
            //4、不通过，响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}